//C++ : $Id: core_tree_test.cpp 23 2010-04-19 20:38:15Z daher.alfawares@gmail.com $
/*
-----------------------------------------------------------------------
	XR Core
---------------

Copyright 2006 Daher Alfawares

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

-----------------------------------------------------------------------
*/

#include <xr/core_tree>

#include <iostream>
#include <algorithm>

#ifdef __XR_CORE_TREE__BOOST_SERIALIZATION__
#include <fstream>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#endif __XR_CORE_TREE__BOOST_SERIALIZATION__

namespace xr { namespace test
	{

	namespace regular
		{

		template<typename _Tt> std::ostream& print_tree( std::ostream& _Stream, _Tt& _Tree )
			{
			_Tt::preorder_iterator Iter;
			for( Iter = _Tree.begin_preorder(); Iter != _Tree.end_preorder(); ++Iter )
				{
				for( std::size_t i=0; i<  _Tree.depth( Iter ); i++ )
					_Stream << "- ";

				_Stream << static_cast<_Tt::value_type>(*Iter) << std::endl;
				}
			return _Stream;
			}

		template<> std::ostream& print_tree< xr::core::tree<std::string> >( std::ostream& _Stream, xr::core::tree<std::string>& _Tree )
			{
			xr::core::tree<std::string>::preorder_iterator Iter;
			for( Iter = _Tree.begin_preorder(); Iter != _Tree.end_preorder(); ++Iter )
				{
				for( xr::core::tree<std::string>::size_type i=0; i< _Tree.depth( Iter ); i++ )
					_Stream << "- ";

				_Stream << Iter->c_str() << std::endl;
				}
			return _Stream;
			}

		void PrintCube(int n)
			{
			std::cout << double( n * n * n ) << " " ;
			}

			// prints the cube of integer n
		void PrintLeafs( const std::string& T )
			{
			std::cout << T.c_str() << " " ;
			}

		}

	namespace constant
		{
		template<typename _Tt> std::ostream& print_tree( std::ostream& _Stream, const _Tt& _Tree )
			{
			_Tt::const_preorder_iterator Iter;
			for( Iter = _Tree.begin_preorder(); Iter != _Tree.end_preorder(); ++Iter )
				{
				for( std::size_t i=0; i<  _Tree.depth( Iter ); i++ )
					_Stream << "- ";

				_Stream << static_cast<_Tt::value_type>(*Iter) << std::endl;
				}
			return _Stream;
			}

		template<> std::ostream& print_tree< xr::core::tree<std::string> >( std::ostream& _Stream, const xr::core::tree<std::string>& _Tree )
			{
			xr::core::tree<std::string>::const_preorder_iterator Iter;
			for( Iter = _Tree.begin_preorder(); Iter != _Tree.end_preorder(); ++Iter )
				{
				for( xr::core::tree<std::string>::size_type i=0; i< _Tree.depth( Iter ); i++ )
					_Stream << "- ";

				_Stream << static_cast<std::string>(*Iter).c_str() << std::endl;
				}
			return _Stream;
			}

		void PrintCube( const int n )
			{
			std::cout << double( n * n * n ) << " " ;
			}

			// prints the cube of integer n
		void PrintLeafs( const std::string& T )
			{
			std::cout << T.c_str() << " " ;
			}
		}

	inline std::ostream& operator << ( std::ostream& _Stream, xr::core::tree<int>& _Tree )				{ return regular::print_tree( _Stream, _Tree ); }
	inline std::ostream& operator << ( std::ostream& _Stream, xr::core::tree<std::string>& _Tree )		{ return regular::print_tree( _Stream, _Tree ); }
	inline std::ostream& operator << ( std::ostream& _Stream, const xr::core::tree<int>& _Tree )		{ return constant::print_tree( _Stream, _Tree ); }
	inline std::ostream& operator << ( std::ostream& _Stream, const xr::core::tree<std::string>& _Tree ){ return constant::print_tree( _Stream, _Tree ); }

	void tree()
		{
		std::cout << "\n------------------------------------------\n";
		std::cout << "\n-               core::tree               -\n";
		std::cout << "\n------------------------------------------\n";

		core::tree<int>									TI;
														TI.push_back(0);
		core::tree<int>::reference TI10		=			TI.push_back(10);
		core::tree<int>::reference TI1010	=			TI10.push_back(1010);
														TI1010.push_back(101010);
														TI1010.push_back(101020);
		core::tree<int>::reference TI101030	=			TI1010.push_back(101030);
														TI101030.push_back(10103020);
														TI101030.push_front(10103010);
														TI10.push_back(1020);
		core::tree<int>::reference TI20		=			TI.push_back(20);
		assert( TI20 == 20 );
														TI20.push_back(2010);
														TI20.push_back(2020);

		core::tree<std::string>							TS;
														TS.push_back("0");
		core::tree<std::string>::reference TS10		=	TS.push_back("10");
		core::tree<std::string>::reference TS1010	=	TS10.push_back("1010");
														TS1010.push_back("101010");
														TS1010.push_back("101020");
		core::tree<std::string>::reference TS101030	=	TS1010.push_back("101030");
														TS101030.push_back("10103020");
														TS101030.push_front("10103010");
														TS10.push_back("1020");
		core::tree<std::string>::reference TS20		=	TS.push_back("20");
														TS20.push_back("2010");
														TS20.push_back("2020");

		const core::tree<int>			CTI = TI;
		const core::tree<std::string>	CTS = TS;

		std::cout << "Testing tree<int>:" << std::endl;
		std::cout << TI << std::endl;
		std::cout << TI1010 << std::endl;
		std::cout << "Testing tree<std::string>:" << std::endl;
		std::cout << TS << std::endl;
		std::cout << TS1010 << std::endl;
		std::cout << "Testing const tree<int>:" << std::endl;
		std::cout << CTI << std::endl;
		std::cout << "Testing const tree<std::string>:" << std::endl;
		std::cout << CTS << std::endl;

		std::cout << std::endl;
		std::for_each( TI.begin(), TI.end(), regular::PrintCube );
		std::cout << std::endl;
		std::for_each( CTI.begin(), CTI.end(), constant::PrintCube );

		std::cout << std::endl;
		std::for_each( TS.begin_preorder(), TS.end_preorder(), regular::PrintLeafs );
		std::cout << std::endl;
		std::for_each( CTS.begin_preorder(), CTS.end_preorder(), constant::PrintLeafs );
		std::cout << std::endl;

		core::tree<int>::preorder_iterator ITER;
		ITER = TI.begin_preorder();
		++ITER;
		ITER++;
		++ITER;

			// find item.
		core::tree<int>::preorder_iterator Found0 = std::find_if( TI.begin_preorder(), TI.end_preorder(), std::bind2nd( std::equal_to<int>(), 1010 ) );
		assert( Found0 != TI.end_preorder() );
		assert( *Found0 == 1010 );
		assert( TI.depth( Found0 ) == 1 );

			// remove item.
		std::remove_if( TI.begin_preorder(), TI.end_preorder(), std::bind2nd( std::equal_to<int>(), 1010 ) );

			// find item.
		core::tree<int>::preorder_iterator Found1 = std::find_if( TI.begin_preorder(), TI.end_preorder(), std::bind2nd( std::equal_to<int>(), 1010 ) );
		assert( Found1 == TI.end_preorder() );


#ifdef __XR_CORE_TREE__BOOST_SERIALIZATION__
		std::cout << "\n------------------------------------------\n";
		std::cout << "\n-       core::tree::serialization        -\n";
		std::cout << "\n------------------------------------------\n";

		// write
			{
			std::ofstream ofs("core_tree.test");
			boost::archive::text_oarchive oa(ofs);
			oa << CTI;
			oa << CTS;
			}

		// read
		core::tree<int>			NTI;
		core::tree<std::string>	NTS;
			{
			std::ifstream ifs("core_tree.test");
			boost::archive::text_iarchive ia(ifs);
			ia >> NTI;
			ia >> NTS;
			}

		std::cout << NTS << std::endl;
		std::cout << NTI << std::endl;
#endif __XR_CORE_TREE__BOOST_SERIALIZATION__

		std::cout << "\n----------------------------------------------\n";
		}

	} /* test */ } /* xr */